package com.nchu.learn.netty.handler;

import com.nchu.learn.netty.enums.MessageTypeEnum;
import com.nchu.learn.netty.model.Message;
import com.nchu.learn.netty.resolver.*;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author fujianjian
 * @project self-learning
 * @date 2020/1/16 13:55
 */
@Slf4j
public class ClientMessageHandler extends SimpleChannelInboundHandler<Message> {

    private ExecutorService es = Executors.newSingleThreadExecutor();
    private MessageResolverFactory resolverFactory = MessageResolverFactory.getInstance();


    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Message message) throws Exception {
        Resolver resolver = resolverFactory.getResolver(message);
        Message result = resolver.resolve(message);
        channelHandlerContext.writeAndFlush(result);
    }


    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        resolverFactory.registerResolver(new RequestMessageResolver());
        resolverFactory.registerResolver(new ResponseMessageResolver());
        resolverFactory.registerResolver(new PingMessageResolver());
        resolverFactory.registerResolver(new PongMessageResolver());
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            // 空闲时发送心跳
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            if (idleStateEvent.state() == IdleState.READER_IDLE) {
                // 当读空闲, 当前服务没有发生读取事件，没有消息发送到当前管道。则发送一个Ping消息检测下服务端是否还在
                Message message = new Message();
                message.setMessageType(MessageTypeEnum.PING);
                message.setBody("PING REQ");
                ctx.writeAndFlush(message);
            } else if (idleStateEvent.state() == IdleState.WRITER_IDLE) {
                // 当前写空闲，当前服务没有写入消息到管道中则关闭管道
                ctx.channel();
            }
        }


    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 当通道被激活时，异步启线程模拟随机发送消息
        es.execute(new MessagerSender(ctx));
    }


    private static final class MessagerSender implements Runnable {
        private static final AtomicInteger counter = new AtomicInteger(1);
        private volatile ChannelHandlerContext ctx;

        public MessagerSender(ChannelHandlerContext ctx) {
            this.ctx = ctx;
        }

        @Override
        public void run() {
            try {

                while (true) {
                    TimeUnit.SECONDS.sleep(new Random().nextInt(3));
                    Message message = new Message();
                    message.setMessageType(MessageTypeEnum.REQUEST);
                    message.setBody(String.format("this is my %d message.", counter.getAndIncrement()));
                    message.addAttachment("name", "zhaoqingsong");
                    message.addAttachment("timestamp",
                            LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                    log.info("mock sender request:{}", message.getBody());
                    this.ctx.writeAndFlush(message);

                }

            } catch (Exception e) {

            }

        }
    }
}

